
package test;

import fv3tk.Animator;
import fv3tk.Fv3Screen;

import javax.media.opengl.GL2;

import com.sun.javafx.newt.MouseEvent;

/**
 * The gears demo in fv3.
 * @author Brian Paul
 * @author Ron Cemer
 * @author Sven Goethel
 * @author jdp@syntelos
 * @version 1.2 1999/10/21
 */
public class Gears
    extends fv3tk.Fv3Canvas
{
    public static void main(String[] argv){
        try {
            Gears gears = new Gears();
            Animator animator = new Animator(gears);
            animator.start();
        }
        catch (Exception exc){
            exc.printStackTrace();
            System.exit(1);
        }
    }


    private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
    private int gear1, gear2, gear3;
    private float angle = 0.0f;

    private int prevMouseX, prevMouseY;


    public Gears(){
        super();
    }


    public void init(GL2 gl) {

        float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
        float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
        float green[] = { 0.0f, 0.8f, 0.2f, 1.0f };
        float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };

        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0);
        gl.glEnable(GL2.GL_CULL_FACE);
        gl.glEnable(GL2.GL_LIGHTING);
        gl.glEnable(GL2.GL_LIGHT0);
        gl.glEnable(GL2.GL_DEPTH_TEST);

        this.gear1 = gl.glGenLists(1);
        gl.glNewList(this.gear1, GL2.GL_COMPILE);
        gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0);
        Gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f);
        gl.glEndList();
            
        this.gear2 = gl.glGenLists(1);
        gl.glNewList(gear2, GL2.GL_COMPILE);
        gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0);
        Gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f);
        gl.glEndList();
            
        this.gear3 = gl.glGenLists(1);
        gl.glNewList(this.gear3, GL2.GL_COMPILE);
        gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0);
        Gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
        gl.glEndList();
            
        gl.glEnable(GL2.GL_NORMALIZE);

        Fv3Screen fv3s = Fv3Screen.Current();
        float aspect = (float)(fv3s.width / fv3s.height);

        gl.glMatrixMode(GL2.GL_PROJECTION);

        gl.glLoadIdentity();
        gl.glFrustum(-1.0f, 1.0f, -aspect, aspect, 5.0f, 60.0f);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0.0f, 0.0f, -40.0f);
    }
    
    public void display(GL2 gl) {

        this.angle += 2.0f;

        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

        gl.glPushMatrix();
        gl.glRotatef(this.view_rotx, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(this.view_roty, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(this.view_rotz, 0.0f, 0.0f, 1.0f);

        gl.glPushMatrix();
        gl.glTranslatef(-3.0f, -2.0f, 0.0f);
        gl.glRotatef(this.angle, 0.0f, 0.0f, 1.0f);
        gl.glCallList(this.gear1);
        gl.glPopMatrix();

        gl.glPushMatrix();
        gl.glTranslatef(3.1f, -2.0f, 0.0f);
        gl.glRotatef(-2.0f * this.angle - 9.0f, 0.0f, 0.0f, 1.0f);
        gl.glCallList(this.gear2);
        gl.glPopMatrix();

        gl.glPushMatrix();
        gl.glTranslatef(-3.1f, 4.2f, 0.0f);
        gl.glRotatef(-2.0f * this.angle - 25.0f, 0.0f, 0.0f, 1.0f);
        gl.glCallList(this.gear3);
        gl.glPopMatrix();

        gl.glPopMatrix();
    }


    public void mousePressed(MouseEvent e) {
        this.prevMouseX = e.getX();
        this.prevMouseY = e.getY();
    }
    public void mouseDragged(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        Fv3Screen fv3s = Fv3Screen.Current();

        float thetaY = 360.0f * ((float)(x-prevMouseX)/(float)fv3s.width);
        float thetaX = 360.0f * ((float)(prevMouseY-y)/(float)fv3s.height);
    
        this.prevMouseX = x;
        this.prevMouseY = y;

        this.view_rotx += thetaX;
        this.view_roty += thetaY;
    }

    private static void Gear(GL2 gl, float inner_radius, float outer_radius,
                             float width, int teeth, float tooth_depth)
    {
        int i;
        float r0, r1, r2;
        float angle, da;
        float u, v, len;

        r0 = inner_radius;
        r1 = outer_radius - tooth_depth / 2.0f;
        r2 = outer_radius + tooth_depth / 2.0f;
            
        da = 2.0f * (float) Math.PI / teeth / 4.0f;
            
        gl.glShadeModel(GL2.GL_FLAT);

        gl.glNormal3f(0.0f, 0.0f, 1.0f);

        /* draw front face */
        gl.glBegin(GL2.GL_QUAD_STRIP);
        for (i = 0; i <= teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
            if (i < teeth){
                gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
                gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
            }
        }
        gl.glEnd();
        
        /* draw front sides of teeth */
        gl.glBegin(GL2.GL_QUADS);
        for (i = 0; i < teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
        }
        gl.glEnd();
        
        /* draw back face */
        gl.glBegin(GL2.GL_QUAD_STRIP);
        for (i = 0; i <= teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
            gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
            gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
        }
        gl.glEnd();
        
        /* draw back sides of teeth */
        gl.glBegin(GL2.GL_QUADS);
        for (i = 0; i < teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
        }
        gl.glEnd();
    
        /* draw outward faces of teeth */
        gl.glBegin(GL2.GL_QUAD_STRIP);
        for (i = 0; i < teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
            u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle);
            v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle);
            len = (float)Math.sqrt(u * u + v * v);
            u /= len;
            v /= len;
            gl.glNormal3f(v, -u, 0.0f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
            gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f);
            gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
            u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da);
            v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da);
            gl.glNormal3f(v, -u, 0.0f);
            gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f);
            gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
            gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
        }
        gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f);
        gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f);
        gl.glEnd();
    
        gl.glShadeModel(GL2.GL_SMOOTH);
    
        /* draw inside radius cylinder */
        gl.glBegin(GL2.GL_QUAD_STRIP);
        for (i = 0; i <= teeth; i++){
            angle = i * 2.0f * (float) Math.PI / teeth;
            gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f);
            gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
            gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
        }
        gl.glEnd();
    }
}
